package org.esmerilprogramming.overtown.scanner; import org.esmerilprogramming.overtown.annotation.Controller; import org.esmerilprogramming.overtown.annotation.path.*; import org.esmerilprogramming.overtown.annotation.path.InternalError; import org.esmerilprogramming.overtown.annotation.session.SessionListener; import org.esmerilprogramming.overtown.http.ErrorHandler; import org.esmerilprogramming.overtown.scanner.exception.PackageNotFoundException; import org.esmerilprogramming.overtown.server.Configuration; import org.esmerilprogramming.overtown.server.ConfigurationHolder; import org.jboss.logging.Logger; import org.reflections.Reflections; import javax.servlet.http.HttpServlet; import javax.websocket.server.ServerEndpoint; import java.io.IOException; import java.util.Arrays; import java.util.LinkedHashSet; import java.util.Set; /** * * @author efraimgentil (efraim.gentil@gmail.com) */ public class PackageScanner { private Configuration configuration; private final String MANAGEMENT_PACKAGE = "org.esmerilprogramming.overtown.management"; private final Logger logger = Logger.getLogger(PackageScanner.class); public ScannerResult scan( String packageToSearch ) throws PackageNotFoundException, IOException { configuration = ConfigurationHolder.getInstance().getConfiguration(); return scanPackage( packageToSearch ); } protected ScannerResult scanPackage(String packageToSearch) throws PackageNotFoundException, IOException { Reflections reflections = new Reflections( packageToSearch ); Set<Class<?>> controllers = reflections.getTypesAnnotatedWith(Controller.class); Set<Class<?>> serverEndpoints = reflections.getTypesAnnotatedWith(ServerEndpoint.class); Set<Class<?>> sessionListeners = reflections.getTypesAnnotatedWith(SessionListener.class); Set<Class<? extends HttpServlet>> servlets = reflections.getSubTypesOf(HttpServlet.class); ScannerResult scannerResult = new ScannerResult(); scannerResult = mapControllers( scannerResult , filtrateClasses(controllers) ); for(Class<?> c : filtrateClasses(serverEndpoints) ){ scannerResult.addServerEndpointClass(c); } for(Class<?> c : filtrateClasses(sessionListeners) ){ scannerResult.addSessionListener(c); } for(Class c : filtrateClasses( servlets ) ){ scannerResult.addServletClass(c); } scannerResult.setNotFoundClass(findErrorHandler(NotFound.class, reflections)); scannerResult.setMethodNotAllowedClass(findErrorHandler(MethodNotAllowed.class, reflections)); scannerResult.setInternalErrorClass( findErrorHandler( InternalError.class , reflections )); return scannerResult; } protected Class<? extends ErrorHandler> findErrorHandler( Class annotationClass , Reflections reflections){ Set<Class<?>> result = reflections.getTypesAnnotatedWith( annotationClass ); if(result.size() >= 1){ Class c = result.iterator().next(); if(!Arrays.asList( c.getInterfaces() ).contains(ErrorHandler.class)){ logger.warn("The class '" + c.getName() + "' is mapped as @" + annotationClass.getSimpleName() +" but doesn't implements org.esmerilprogramming.overtown.http.ErrorHandler it will be disconsidered"); }else{ if(result.size() > 2){ logger.info("Was found more than one class with @NotFound annotation, only the first will be considered"); } return c; } } return null; } protected ScannerResult mapControllers( ScannerResult scannerResult , Set<Class<?>> controllers){ ControllerScanner scanner = new ControllerScanner(); for(Class<?> controller : controllers){ scannerResult.addControllerMapping( scanner.scanControllerForMapping(controller) ); } return scannerResult; } protected <T> Set<Class<? extends T>> filtrateClasses(Set<Class<? extends T>> classes){ if( !configuration.getRunManagement() ){ Set<Class<?>> classesToRemove = new LinkedHashSet<>(); for ( Class<?> c : classes){ if( c.getPackage().getName().startsWith( MANAGEMENT_PACKAGE ) ){ classesToRemove.add(c); } } classes.removeAll( classesToRemove ); } return classes; } }